XDL PlanetView 활용 두 번째

NXPlanetView를 활용하여 2D 및 3D 환경에서 다양한 측정방법을 구현해 보고, 사용자 정의 설정한 정점에 대한 거리 및 각도 측정도 구현해 봅니다.

들어가기 전에

설치 프로그램으로 배포되는 XDL 엔진은 Visual Studio 2022 x64 Release 버전으로, Visual Studio 2022 이상의 버전에서 사용 가능하다.
아래의 설명은 Visual Studio 2022를 기준으로 하겠다.

1 기본 프로그램 작성
1.1 Visual Studio 2022를 이용하여 예제 “XDL_PlanetView1”의 "기본 프로그램 작성” 방법을 참고로 기본 프로젝트를 생성한다.

프로젝트 이름은 “XDL_PlanetView2”로 한다.

1.2 Pixoneer.NXDL.NCC을 이용하기 위해서 “NXDLcc.dll”을 프로젝트의 참조로 추가한다.

참조 추가 방법은 “XDL_PlanetView1” 튜토리얼을 참고한다.

2 프로그램 디자인
번호 Name Control type
(1) menuStrip1 MenuStrip
(2) splitContainter1 SplitContainer
(3) nxPlanetView2D NXPlanetView
(4) nxPlanetView3D NXPlanetView
(5) nxPlanetLayer2D NXPlanetLayer
2.1 [도구 상자]의 “MenuStrip”를 선택하고 Form1에 끌어다가 놓는다.

Form1에 menuStrip1이 추가된다. Form의 상단을 클릭하면 아래와 같이 메뉴를 추가할 수 있도록 바뀐다.

기능을 위한 메뉴를 입력하고 이에 대한 Name도 설정한다. 예제의 메뉴 구성은 아래와 같다.

Text Name
거리(단선) 측정 Measure2DLineToolStripMenuItem
거리(폴리라인) 측정 Measure2DPolyLineToolStripMenuItem
면적 측정 Measure2DAreaToolStripMenuItem
각도 측정(진북방향) Measure2DAngleToolStripMenuItem
각도 측정(3점 이용) Measure2DAngle3PtToolStripMenuItem
원형 측정 Measure2DCircleToolStripMenuItem
Text Name
거리(단선) 측정 Measure3DLineToolStripMenuItem
거리(폴리라인) 측정 Measure3DPolyLineToolStripMenuItem
면적 측정 Measure3DAreaToolStripMenuItem
각도 측정(진북방향) Measure3DAngleToolStripMenuItem
각도 측정(3점 이용) Measure3DAngle3PtToolStripMenuItem
원형 측정 Measure3DCircleToolStripMenuItem
Text Name
거리 및 각도 측정 UserDefinedMeasureToolStripMenuItem
2.2 나머지 컨트롤은 “XDL_PlanetView1”을 참고하여 추가한다.
2.3 nxPlanetView3D 컨트롤을 선택하고 [속성] 창의 “EarthMode”를 “Planet3D”로 설정한다.

NXPlanetView의 EarthMode는 “Planet2D”이다. Earth모드를 “Planet3D”로 설정하면 PlanetView는 3차원 도시 모드로 변경된다.

2.4 솔루션을 빌드하고 실행한다.
3 기능 및 이벤트 추가
3.1 Form1을 선택하고 [속성]창 - [이벤트]메뉴를 선택한 뒤 “Load” 이벤트를 더블 클릭한다.

Form1_Load 함수와 함께 아래와 같이 코드를 추가한다.

C#

                                using Pixoneer.NXDL;
using Pixoneer.NXDL.NGR;
using Pixoneer.NXDL.NXPlanet; 
using Pixoneer.NXDL.NCC;

namespace XDL_PlanetView2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            nxPlanetView2D.BackColor = Color.Black;
            nxPlanetView3D.BackColor = Color.Black;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            XGeoPoint gpEye = XGeoPoint.FromDegree(127.4, 38.0, 1500000);
            // Planet2D 모드의 camera 위치 설정
            nxPlanetView2D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0));
            // Planet3D 모드의 camera 위치 설정
            nxPlanetView3D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0), XAngle.FromDegree(-90.0), XAngle.FromDegree(0.0));

            // PlanetView의 측정 단위 설정
            // 거리 측정 단위
            nxPlanetView3D.ToolboxDistUnit = NXPlanetView.eToolboxDistUnit.Mile;
            // 면적 측정 단위
            nxPlanetView3D.ToolboxAreaUnit = NXPlanetView.eToolboxAreaUnit.SquareKiloMeter;

            nxPlanetView2D.RefreshScreen();
            nxPlanetView3D.RefreshScreen();
        }
    }
}

                        
3.2 “2D Measurement/3D Measurement/사용자 정의”의 하위 메뉴를 선택한 후 더블클릭한다.

메뉴에서 마우스로 더블클릭하면 “Click”에 대한 이벤트 함수가 자동 추가된다.

3.3 각 메뉴에 따른 nxPlanetView2D와 nxPlanetView3D의 ToolboxMode를 설정한다.

NXPlanetView의 측정모드로는 2점을 이용한 거리 측정(NXPlanetView.eToolboxMode. DistanceMeasurer), 다중 점을 이용한 거리 측정(eToolboxMode.PathMeasurer), 다중 점을 이용한 면적 측정(eToolboxMode.AreaMeasurer), 두 점의 거리를 반지름으로 한 원형 측정(eToolboxMode.CircleMeasurer), 두 점으로 이루어진 벡터와 진북방향과의 각도 측정(eToolboxMode.AngleMeasurer), 세 점으로 이루어진 각도 측정(eToolboxMode.AngleMeasurer2) 등이 있다.
측정 결과를 표시하는 데에 측정 단위를 설정하려면, 면적에 대해서는 NXPlanetView의 ToolboxAreaUnit 속성을 NXPlanetView.eToolboxAreaUnit 값으로 설정하면 되고, 거리에 대해서는 NXPlanetView의 ToolboxDistUnit 속성을 NXPlanetView.eToolboxDistUnit 값으로 설정한다. 코드는 아래와 같다.

C#

                                private void Measure2DLineToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 두 점을 이용한 거리 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.DistanceMeasurer;
}

private void Measure2DPolyLineToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 다중 점을 이용한 거리 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.PathMeasurer;
}

private void Measure2DAreaToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 다중 점을 이용한 면적 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AreaMeasurer;
}

private void Measure2DAngleToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 두 점으로 이뤄진 벡터와 진북방향과의 각도 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer;
}

private void Measure2DAngle3PtToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 세 점으로 이루어진 각도 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer2;
}

private void Measure2DCircleToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 두 점의 거리를 반지름으로 하는 원형 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.CircleMeasurer;
}

private void Measure3DLineToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 두 점을 이용한 거리 측정
    nxPlanetView3D.ToolboxMode = NXPlanetView.eToolboxMode.DistanceMeasurer;
}

private void Measure3DPolyLineToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 다중 점을 이용한 거리 측정
    nxPlanetView3D.ToolboxMode = NXPlanetView.eToolboxMode.PathMeasurer;
}

private void Measure3DAreaToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 다중 점을 이용한 면적 측정
    nxPlanetView3D.ToolboxMode = NXPlanetView.eToolboxMode.AreaMeasurer;
}

private void Measure3DAngleToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 두 점으로 이뤄진 벡터와 진북방향과의 각도 측정
    nxPlanetView3D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer;
}

private void Measure3DAngle3PtToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 세 점으로 이루어진 각도 측정
    nxPlanetView3D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer2;
}

private void Measure3DCircleToolStripMenuItem_Click(object sender, EventArgs e)
{
    // 두 점의 거리를 반지름으로 하는 원형 측정
    nxPlanetView3D.ToolboxMode = NXPlanetView.eToolboxMode.CircleMeasurer;
}

                        
3.4 사용자 정의 측정을 위한 변수를 추가하고 UserDefinedMeasureToolStripMenuItem 이벤트 함수에서 초기화한다.

사용자 정의 측정 여부를 설정하는 “bool userMeasure”와 각도 측정을 위한 세 변수 “XGeoPoint posMeasure0, posMeasure1, posMeasure2”를 생성하고 초기화한다.

C#

                                public partial class Form1 : Form
{
    bool userMeasure = false;
    int countPos = 0;
    XGeoPoint posAngle0, posAngle1, posAngle2;    // index 0 : start, index 1 : center, index 2 : end
    public Form1()
    {
        InitializeComponent();
        nxPlanetView2D.BackColor = Color.Black;
        nxPlanetView3D.BackColor = Color.Black;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        XGeoPoint gpEye = XGeoPoint.FromDegree(127.4, 38.0, 1500000);
        // Planet2D 모드의 camera 위치 설정
        nxPlanetView2D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0));
        // Planet3D 모드의 camera 위치 설정
        nxPlanetView3D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0), XAngle.FromDegree(-90.0), XAngle.FromDegree(0.0));

        // PlanetView의 측정 단위 설정
        // 거리 측정 단위
        nxPlanetView3D.ToolboxDistUnit = NXPlanetView.eToolboxDistUnit.Mile;
        // 면적 측정 단위
        nxPlanetView3D.ToolboxAreaUnit = NXPlanetView.eToolboxAreaUnit.SquareKiloMeter;
         
        nxPlanetView2D.RefreshScreen();
        nxPlanetView3D.RefreshScreen();

        // 사용자 정의 측정을 위한 변수 초기화
        userMeasure = false;
        countPos = 0;
    }

    private void UserDefinedMeasureToolStripMenuItem_Click(object sender, EventArgs e)
    {
        userMeasure = !userMeasure;
        countPos = 0;
    }


                        
3.5 각도 및 거리를 측정하는 함수를 이용하기 위해서 “using Pixoneer.NXDL.NCC;” 구문을 추가한다.

WGS84체를 반영한 거리를 측정하는 함수는 Xcc.CalcGeodeticDistance이며, 각도를 측정하는 함수는 Xcc.CalcGeodeticAngle이다.

3.6 nxPlanetLayer2D을 선택하여 “OnWndProc” 이벤트와 “OnRender” 이벤트 함수를 추가하여 코드를 작성한다.

OnWndProc 이벤트는 NXPlanetLayer가 추가되어 있는 View의 윈도우 이벤트를 외부에서 받아서 사용할 수 있도록 한다.
OnRender는 NXPlanetLayer가 추가되어 있는 View의 Rendering이 완료된 후 어플리케이션에서 추가적인 작업을 구현해야 할 필요가 있을 때 사용하면 된다. 왼쪽 버튼이 클릭할 때마다 각도 측정을 위한 점을 차례대로 설정하고 3점이 모두 설정되면 계산결과를 Visual Studio 2022 출력창에 출력하도록 한다. 또한 2점 이상인 경우 화면에 붉은 선으로 도시한다. 코드는 아래와 같다.

C#

                                private bool nxPlanetLayer2D_OnWndProc(object sender, NXPlanetDrawArgs e, ref Message m)
{
    if (m.Msg == Pixoneer.NXDL.XWndMsg.XWM_LBUTTONDOWN)
    {
        if (userMeasure)
        {
            double x = Pixoneer.NXDL.XWndMsg.GetLowValue(m.LParam);
            double y = Pixoneer.NXDL.XWndMsg.GetHighValue(m.LParam);

            XGeoPoint gpPos = nxPlanetView2D.ScreenToGeographic(x, y);
            if (countPos == 0)
            {
                posAngle0 = gpPos;
            }
            else if (countPos == 1)
            {
                posAngle1 = gpPos;
            }
            else if (countPos == 2)
            {
                posAngle2 = gpPos;

                // 두 선분의 길이와 3 점으로 이루어지는 각도 계산
                double distance = 0.0;
                distance += Xcc.CalcGeodeticDistance(XAngle.FromDegree(posAngle0.lond), XAngle.FromDegree(posAngle0.latd), XAngle.FromDegree(posAngle1.lond), XAngle.FromDegree(posAngle1.latd));
                distance += Xcc.CalcGeodeticDistance(XAngle.FromDegree(posAngle1.lond), XAngle.FromDegree(posAngle1.latd), XAngle.FromDegree(posAngle2.lond), XAngle.FromDegree(posAngle2.latd));

                double angle = 0.0;
                angle = Xcc.CalcGeodeticAngle(XAngle.FromDegree(posAngle1.lond), XAngle.FromDegree(posAngle1.latd), XAngle.FromDegree(posAngle0.lond), XAngle.FromDegree(posAngle0.latd), XAngle.FromDegree(posAngle2.lond), XAngle.FromDegree(posAngle2.latd));

                System.Diagnostics.Debug.WriteLine("Distance : " + distance.ToString());
                System.Diagnostics.Debug.WriteLine("Angle    : " + angle.ToString());
            }

            countPos++;

            nxPlanetView2D.RefreshScreen();
        }
    }
    return default(bool);
}

private bool nxPlanetLayer2D_OnRender(object sender, NXPlanetDrawArgs e)
{
    if (!userMeasure) return false;

    if (countPos > 1)
    {
        e.Graphics.glDisable(XGraphics.GL_DEPTH_TEST);
        e.Graphics.glEnable(XGraphics.GL_BLEND);
        e.Graphics.glBlendFunc(XGraphics.GL_SRC_ALPHA, XGraphics.GL_ONE_MINUS_SRC_ALPHA);

        e.Graphics.glPushMatrix();

        e.Graphics.glColor3f(1.0f, 0.0f, 0.0f);
        e.Graphics.glLineWidth(3);
        e.Graphics.glBegin(XGraphics.GL_LINE_STRIP);

        XVertex3d posWorld = nxPlanetView2D.GeographicToWorld(posAngle0);
        e.Graphics.glVertex3d(posWorld - e.WOS);

        posWorld = nxPlanetView2D.GeographicToWorld(posAngle1);
        e.Graphics.glVertex3d(posWorld - e.WOS);

        if (countPos >= 3)
        {
            posWorld = nxPlanetView2D.GeographicToWorld(posAngle2);
            e.Graphics.glVertex3d(posWorld - e.WOS);
        }

        e.Graphics.glEnd();
        e.Graphics.glColor3f(1.0f, 1.0f, 1.0f);
        e.Graphics.glPopMatrix();
        e.Graphics.glEnable(XGraphics.GL_DEPTH_TEST);
    }

    return default(bool);
}

                        
3.7 솔루션을 빌드하고 실행한다.

2D Measurement의 “거리(폴리라인) 측정” 메뉴를 선택한 뒤 nxPlanetView2D 위에서 마우스 왼쪽 버튼을 클릭하면서 측정하고자 하는 정점을 설정한다. 아래 그림과 같이 측정 결과가 각 선분 요소에 도시된다.

3D Measurement의 “각도 측정(진북방향)” 메뉴를 선택한 뒤 nxPlanetView3D 위에서 마우스 왼쪽 버튼을 클릭하고 마우스를 움직이면 진북방향과 이루는 각도가 화면에 도시되며 마우스 왼쪽 버튼을 더블 클릭하여 측정을 종료한다.

사용자 정의 메뉴의 “거리 및 각도 측정”을 선택한 뒤 nxPlanetView2D 위에서 마우스 왼쪽 버튼을 클릭하면 2점 이상부터 화면에 붉은 실선이 도시되고, 3점이 선택되면 Visual Studio 2022의 출력창에 측정결과가 나타난다.

측정결과의 단위는 거리의 경우 meter, 각도의 경우 ˚(degree)이다.

1 기본 프로그램 작성
1.1 Visual Studio 2022를 이용하여 예제 “XDL_PlanetView1”의 “기본 프로그램 작성” 방법을 참고로 기본 프로젝트를 생성한다.

프로젝트 이름은 “XDL_PlanetView2”로 한다.

1.2 Pixoneer.NXDL.NCC을 이용하기 위해서 “NXDLcc.dll”을 프로젝트의 참조로 추가한다.

참조 추가 방법은 “XDL_PlanetView1” 튜토리얼을 참고한다.

2 프로그램 디자인
번호 Name Control type
(1) menu Menu
(2) splitContainter1 GridSplitter
(3) nxPlanetView2D NXPlanetView
(4) nxPlanetView3D NXPlanetView
(5) nxPlanetLayer2D NXPlanetLayer
2.1 MainWindow.xaml 창에서 기본으로 생성된 Grid 레이아웃에 Grid.RowDefinition을 이용하여 Grid를 두 개로 나누어 생성한다. 첫 번째 Grid에 Menu를 배치한다.

2D measurement는 아래와 같은 하부 메뉴를 갖는다. 아래 표를 참고하여 메뉴를 생성하도록 한다.

Text Name
거리(단선) 측정 Measure2DLineToolStripMenuItem
거리(폴리라인) 측정 Measure2DPolyLineToolStripMenuItem
면적 측정 Measure2DAreaToolStripMenuItem
각도 측정(진북방향) Measure2DAngleToolStripMenuItem
각도 측정(3점 이용) Measure2DAngle3PtToolStripMenuItem
원형 측정 Measure2DCircleToolStripMenuItem

3D measurement에서의 메뉴 구성은 아래와 같다. 아래의 표를 참고 하여 메뉴를 구성한다.

Text Name
거리(단선) 측정 Measure3DLineToolStripMenuItem
거리(폴리라인) 측정 Measure3DPolyLineToolStripMenuItem
면적 측정 Measure3DAreaToolStripMenuItem
각도 측정(진북방향) Measure3DAngleToolStripMenuItem
각도 측정(3점 이용) Measure3DAngle3PtToolStripMenuItem
원형 측정 Measure3DCircleToolStripMenuItem

마지막으로 사용자 정의 메뉴를 생성한다.

Text Name
거리 및 각도 측정 UserDefinedMeasureToolStripMenuItem
2.2 다음으로 두 번째 Row Grid에 Grid.ColumnDefinition을 이용하여 세 개의 Column을 생성한다. 첫 번째 Column에는 NXPlanetView와 NXPlanetLayer를 배치하고 두 번째 Column은 GridSpiltter을 놓는다. 세 번째 Column은 NXPlanetView 을 배치한다.
2.3 nxPlanetView3D 컨트롤을 선택하고 [속성] 창의 “EarthMode”를 “Planet3D”로 설정한다.

NXPlanetView의 EarthMode는 “Planet2D”이다. Earth모드를 “Planet3D”로 설정하면 PlanetView는 3차원 도시 모드로 변경된다.

2.4 솔루션을 빌드하고 실행한다.
3 기능 및 이벤트 추가
3.1 Window 창을 선택하고 [속성] 창 - [이벤트] 메뉴를 선택한 뒤 “Loaded” 이벤트를 더블 클릭한다.

“Loaded” 이벤트를 더블 클릭하면, “Window_Loaded” 함수가 자동적으로 추가되고 아래와 같이 추가적인 기능을 구현할 수 있도록 MainWindow.xaml.cs의 코드로 이동하는 것을 확인할 수 있다. 아래와 같이 코드를 추가한다.

C#

                                using Pixoneer.NXDL;
using Pixoneer.NXDL.NGR;
using Pixoneer.NXDL.NXPlanet; 
using Pixoneer.NXDL.NCC;

namespace XDL_PlanetView2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            nxPlanetView2D.BackColor = System.Drawing.Color.Black;
            nxPlanetView3D.BackColor = System.Drawing.Color.Black;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            XGeoPoint gpEye = XGeoPoint.FromDegree(127.4, 38.0, 1500000);
            // 카메라 위치 설정
            nxPlanetView2D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0));
            nxPlanetView3D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0), XAngle.FromDegree(-90.0), XAngle.FromDegree(0.0));

            nxPlanetView3D.ToolboxDistUnit = NXPlanetView.eToolboxDistUnit.Mile; // 거리 측정 단위
            nxPlanetView3D.ToolboxAreaUnit = NXPlanetView.eToolboxAreaUnit.SquareKiloMeter; // 면적 측정 단위

            nxPlanetView2D.RefreshScreen();
            nxPlanetView3D.RefreshScreen();
        }
    }
}

                        
3.2 “2D Measurement/3D Measurement/사용자 정의”의 하위 메뉴를 선택한 후 더블클릭한다.

메뉴에서 마우스로 더블클릭하면 “Click”에 대한 이벤트 함수가 자동 추가된다.

3.3 각 메뉴에 따른 nxPlanetView2D와 nxPlanetView3D의 ToolboxMode를 설정한다.

NXPlanetView의 측정모드로는 2점을 이용한 거리 측정(NXPlanetView.eToolboxMode. DistanceMeasurer), 다중 점을 이용한 거리 측정(eToolboxMode.PathMeasurer), 다중 점을 이용한 면적 측정(eToolboxMode.AreaMeasurer), 두 점의 거리를 반지름으로 한 원형 측정(eToolboxMode.CircleMeasurer), 두 점으로 이루어진 벡터와 진북방향과의 각도 측정(eToolboxMode.AngleMeasurer), 세 점으로 이루어진 각도 측정(eToolboxMode.AngleMeasurer2) 등이 있다.
측정 결과를 표시하는 데에 측정 단위를 설정하려면, 면적에 대해서는 NXPlanetView의 ToolboxAreaUnit 속성을 NXPlanetView.eToolboxAreaUnit 값으로 설정하면 되고, 거리에 대해서는 NXPlanetView의 ToolboxDistUnit 속성을 NXPlanetView.eToolboxDistUnit 값으로 설정한다. 코드는 아래와 같다.

C#

                                private void Measure2DLineMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 두 점을 이용한 거리 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.DistanceMeasurer;
}

private void Measure2DPolyLineMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 다중 점을 이용한 거리 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.PathMeasurer;
}

private void Measure2DAreaMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 다중 점을 이용한 면적 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AreaMeasurer;
}

private void Measure2DAngleMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 두 점으로 이뤄진 벡터와 진북방향과의 각도 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer;
}

private void Measure2DAngle3PtMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 세 점으로 이루어진 각도 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer2;
}

private void MMeasure2DCircleMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 두 점의 거리를 반지름으로 하는 원형 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.CircleMeasurer;
}

private void Measure3DLineMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 두 점을 이용한 거리 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.DistanceMeasurer;
}

private void Measure3DPolyLineMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 다중 점을 이용한 거리 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.PathMeasurer;
}

private void Measure3DAreaMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 다중 점을 이용한 면적 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AreaMeasurer;
}

private void Measure3DAngleMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 두 점으로 이뤄진 벡터와 진북방향과의 각도 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer;
}

private void Measure3DAngle3PtMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 세 점으로 이루어진 각도 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.AngleMeasurer2;
}

private void Measure3DCircleMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 두 점의 거리를 반지름으로 하는 원형 측정
    nxPlanetView2D.ToolboxMode = NXPlanetView.eToolboxMode.CircleMeasurer;
}

                        
3.4 사용자 정의 측정을 위한 변수를 추가하고 UserDefinedMeasureToolStripMenuItem 이벤트 함수에서 초기화한다.

사용자 정의 측정 여부를 설정하는 “bool userMeasure”와 각도 측정을 위한 세 변수 “XGeoPoint posMeasure0, posMeasure1, posMeasure2”를 생성하고 초기화한다.

C#

                                public partial class MainWindow : Window
{
    bool userMeasure = false;
    int countPos = 0;
    XGeoPoint posAngle0, posAngle1, posAngle2;

    public MainWindow()
    {
        InitializeComponent();
        nxPlanetView2D.BackColor = System.Drawing.Color.Black;
        nxPlanetView3D.BackColor = System.Drawing.Color.Black;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        XGeoPoint gpEye = XGeoPoint.FromDegree(127.4, 38.0, 1500000);
        // 카메라 위치 설정
        nxPlanetView2D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0));
        nxPlanetView3D.SetCameraPosition(gpEye, XAngle.FromDegree(0.0), XAngle.FromDegree(-90.0), XAngle.FromDegree(0.0));

        nxPlanetView3D.ToolboxDistUnit = NXPlanetView.eToolboxDistUnit.Mile; // 거리 측정 단위
        nxPlanetView3D.ToolboxAreaUnit = NXPlanetView.eToolboxAreaUnit.SquareKiloMeter; // 면적 측정 단위

        nxPlanetView2D.RefreshScreen();
        nxPlanetView3D.RefreshScreen();

        userMeasure = false;
        countPos = 0;
    }
    private void UserDefinedMeasureMenuItem_Click(object sender, RoutedEventArgs e)
    {
        userMeasure = !userMeasure;
        countPos = 0;
    }

                        
3.5 각도 및 거리를 측정하는 함수를 이용하기 위해서 “using Pixoneer.NXDL.NCC;” 구문을 추가한다.

WGS84체를 반영한 거리를 측정하는 함수는 Xcc.CalcGeodeticDistance이며, 각도를 측정하는 함수는 Xcc.CalcGeodeticAngle이다.

3.6 nxPlanetLayer2D을 선택하여 “OnWndProc” 이벤트와 “OnRender” 이벤트 함수를 추가하여 코드를 작성한다.

OnWndProc 이벤트는 NXPlanetLayer가 추가되어 있는 View의 윈도우 이벤트를 외부에서 받아서 사용할 수 있도록 한다.
OnRender는 NXPlanetLayer가 추가되어 있는 View의 Rendering이 완료된 후 어플리케이션에서 추가적인 작업을 구현해야 할 필요가 있을 때 사용하면 된다. 왼쪽 버튼이 클릭할 때마다 각도 측정을 위한 점을 차례대로 설정하고 3점이 모두 설정되면 계산결과를 Visual Studio 2022 출력창에 출력하도록 한다. 또한 2점 이상인 경우 화면에 붉은 선으로 도시한다. 코드는 아래와 같다.

C#

                                private bool nxPlanetLayer2D_OnRender(object sender, NXPlanetDrawArgs e)
{
    if (!userMeasure) return false;
    if (countPos > 1)
    {
        e.Graphics.glDisable(XGraphics.GL_DEPTH_TEST);
        e.Graphics.glEnable(XGraphics.GL_BLEND);
        e.Graphics.glBlendFunc(XGraphics.GL_SRC_ALPHA, XGraphics.GL_ONE_MINUS_SRC_ALPHA);

        e.Graphics.glPushMatrix();

        e.Graphics.glColor3f(1.0f, 0.0f, 0.0f);
        e.Graphics.glLineWidth(3);
        e.Graphics.glBegin(XGraphics.GL_LINE_STRIP);

        XVertex3d posWorld = nxPlanetView2D.GeographicToWorld(posAngle0);
        e.Graphics.glVertex3d(posWorld - e.WOS);
        posWorld = nxPlanetView2D.GeographicToWorld(posAngle1);
        e.Graphics.glVertex3d(posWorld - e.WOS);

        if (countPos >= 3)
        {
            posWorld = nxPlanetView2D.GeographicToWorld(posAngle2);
            e.Graphics.glVertex3d(posWorld - e.WOS);
        }

        e.Graphics.glEnd();
        e.Graphics.glColor3f(1.0f, 1.0f, 1.0f);
        e.Graphics.glPopMatrix();
        e.Graphics.glEnable(XGraphics.GL_DEPTH_TEST);
    }
    return default(bool);
}

private bool nxPlanetLayer2D_OnWndProc(object sender, NXPlanetDrawArgs e, ref System.Windows.Forms.Message m)
{
    if (m.Msg == XWndMsg.XWM_LBUTTONDOWN)
    {
        if (userMeasure)
        {
            double x = XWndMsg.GetLowValue(m.LParam);
            double y = XWndMsg.GetHighValue(m.LParam);

            XGeoPoint gpPos = nxPlanetView2D.ScreenToGeographic(x, y);
            if (countPos == 0)
            {
                posAngle0 = gpPos;
            }
            else if (countPos == 1)
            {
                posAngle1 = gpPos;
            }
            else if (countPos == 2)
            {
                posAngle2 = gpPos;

                double distance = 0.0;
                distance += Xcc.CalcGeodeticDistance(XAngle.FromDegree(posAngle0.lond), XAngle.FromDegree(posAngle0.latd), XAngle.FromDegree(posAngle1.lond), XAngle.FromDegree(posAngle1.latd));
                distance += Xcc.CalcGeodeticDistance(XAngle.FromDegree(posAngle1.lond), XAngle.FromDegree(posAngle1.latd), XAngle.FromDegree(posAngle2.lond), XAngle.FromDegree(posAngle2.latd));

                double angle = 0.0;
                angle = Xcc.CalcGeodeticAngle(XAngle.FromDegree(posAngle1.lond), XAngle.FromDegree(posAngle1.latd), XAngle.FromDegree(posAngle0.lond), XAngle.FromDegree(posAngle0.latd), XAngle.FromDegree(posAngle2.lond), XAngle.FromDegree(posAngle2.latd));

                System.Diagnostics.Debug.WriteLine("Distance: " + distance.ToString());
                System.Diagnostics.Debug.WriteLine("Angle: " + angle.ToString());
            }
            countPos++;
            nxPlanetView2D.RefreshScreen();
        }
    }
    return default(bool);
}

                        
3.7 솔루션을 빌드하고 실행한다.

2D Measurement의 “거리(폴리라인) 측정” 메뉴를 선택한 뒤 nxPlanetView2D 위에서 마우스 왼쪽 버튼을 클릭하면서 측정하고자 하는 정점을 설정한다. 아래 그림과 같이 측정 결과가 각 선분 요소에 도시된다.

3D Measurement의 “각도 측정(진북방향)” 메뉴를 선택한 뒤 nxPlanetView3D 위에서 마우스 왼쪽 버튼을 클릭하고 마우스를 움직이면 진북방향과 이루는 각도가 화면에 도시되며 마우스 왼쪽 버튼을 더블 클릭하여 측정을 종료한다.

사용자 정의 메뉴의 “거리 및 각도 측정”을 선택한 뒤 nxPlanetView2D 위에서 마우스 왼쪽 버튼을 클릭하면 2점 이상부터 화면에 붉은 실선이 도시되고, 3점이 선택되면 Visual Studio 2022의 출력창에 측정결과가 나타난다.

측정결과의 단위는 거리의 경우 meter, 각도의 경우 ˚(degree)이다.